package shining365.programmableweb.data.app;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.xml.bind.JAXBException;

import org.junit.Test;

import shining365.programmableweb.data.model.Api;


public class CosSimSort extends AppBasic {
	
	public CosSimSort() throws IOException, JAXBException {
		super(true, OrderBy.USE_COUNT);
	}
	
	@Test
	public void sort() {
		//非得用useCounts代替自环数才能取得好结果。其原因值得研究。
		for (int i = 0; i < nNodes; i++) {
			graph[i][i] = useCounts[i];
		}
		
		List<List<Api>> simApisLists = new ArrayList<List<Api>>();
		for (double[] v1 : graph) {
		//对每个api
			//计算其他api与v1的相似度
			final List<Double> s = new ArrayList<Double>(graph.length);
			for (double[] v2 : graph) {
				s.add(cosSim(v1, v2));
			}
			
			//按相似度对api排序
			List<Api> as = new ArrayList<Api>(apis);
			Collections.sort(as, new Comparator<Api>() {
				@Override
				public int compare(Api o1, Api o2) {
					return s.get(indexOf(o2)).compareTo(s.get(indexOf(o1)));
				}
			});
			simApisLists.add(as);
		}
		
		//输出排名靠前的api的相关api
		final int MAX_APIS = 50;
		final int SIM_APIS = 10;
		List<Api> topApis = new ArrayList<Api>();
		for (int i = 0; i < MAX_APIS; i++) {
			topApis.add(apis.get(i));
		}
		for (Api api : topApis) {
			List<Api> simApis = simApisLists.get(indexOf(api));
			int n = SIM_APIS;
			for (int j = 0; j < simApis.size() && n >= 0; j++) {
				if (topApis.contains(simApis.get(j))) {
					n--;
					System.out.printf("%s\t", simApis.get(j).getName());
				}
			}
			System.out.println();
		}
	}
	
	public static double cosSim(double[] v1, double[] v2) {
		return dotProduct(v1, v2) / 
			(Math.sqrt(dotProduct(v1, v1)) * Math.sqrt(dotProduct(v2, v2)));
	}
	
	public static double dotProduct(double[] v1, double[] v2) {
		if (v1.length != v2.length) {
			throw new IllegalArgumentException();
		}
		
		double ret = 0;
		for (int i = 0; i < v1.length; i++) {
			ret += v1[i] * v2[i];
		}
		return ret;
	}
}
